package lion.framework.model.gen;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.WordUtils;

import lion.dev.fun.Funs;
import lion.dev.lang.MapJ;
import lion.framework.core.db.DataSourceManager;
import lion.framework.core.db.DataTable;

/**
 * 根据数据库反向生成Java类
 *
 * @author lion
 * @email hl_0074@sina.com
 * @date 2014年4月8日
 */
public class DataBaseGen {

	public static void pojo(String dbtype, String userName, String password, String server, int port, String database,
			String pkg) throws Exception {
		pojo(dbtype, userName, password, server, port, database, "src", pkg);
	}

	public static void pojo(String dbtype, String userName, String password, String server, int port, String database,
			String base, String pkg) throws Exception {

		String template = IOUtils.toString(Model.class.getResourceAsStream("tmpl/pojo.tmpl"));
		define(dbtype, userName, password, server, port, database, base, pkg, template, null);
	}

	public static void rbm(String dbtype, String userName, String password, String server, int port, String database,
			String pkg) throws Exception {
		rbm(dbtype, userName, password, server, port, database, "src", pkg);
	}

	public static void rbm(String dbtype, String userName, String password, String server, int port, String database,
			String base, String pkg) throws Exception {

		// funs
		Funs fun = new Funs();
		fun.add("insertsql", (Object... args) -> {

			MapJ context = (MapJ) args[0];
			String[][] fields = context.getE("fields");
			StringBuilder sbu = new StringBuilder("insert into  \" + TABLE_NAME + \"(");
			StringBuilder sbu1 = new StringBuilder();
			StringBuilder sbu2 = new StringBuilder();
			boolean b = false;
			for (String[] f : fields) {
				if (f[0].equalsIgnoreCase("id")) {
					continue;
				}
				if (b) {
					sbu1.append(",");
					sbu2.append(",");
				}
				b = true;
				sbu1.append(f[0]);
				sbu2.append(":" + f[0]);
			}
			sbu.append(sbu1.toString() + ")values(" + sbu2.toString() + ")");
			return sbu.toString();
		});
		fun.add("updatesql", (Object... args) -> {

			MapJ context = (MapJ) args[0];
			String[][] fields = context.getE("fields");
			StringBuilder sbu = new StringBuilder("update \" + TABLE_NAME + \" set ");
			boolean b = false;
			for (String[] f : fields) {
				if (f[0].equalsIgnoreCase("id")) {
					continue;
				}
				if (b) {
					sbu.append(",");
				}
				b = true;
				sbu.append(f[0] + "=:" + f[0]);
			}
			sbu.append(" where id=:id");
			return sbu.toString();
		});
		String template = IOUtils.toString(Model.class.getResourceAsStream("tmpl/rbm.tmpl"));
		define(dbtype, userName, password, server, port, database, base, pkg, template, fun);
	}

	public static void define(String dbtype, String userName, String password, String server, int port, String database,
			String base, String pkg, String template, Funs funs)
			throws ClassNotFoundException, SQLException {

		String driver = DataSourceManager.getJDBCDriver(dbtype);
		Class.forName(driver);
		Properties properties = new Properties();
		properties.setProperty("user", userName);
		properties.setProperty("password", password);
		Connection conn = DriverManager.getConnection(
				String.format(DataSourceManager.getDriverURLTemplate(dbtype), server, port, database), properties);
		DatabaseMetaData dmd = conn.getMetaData();
		ResultSet rs = dmd.getTables(null, null, null, new String[] { "TABLE" });
		DataTable dt = new DataTable(rs);

		for (MapJ row : dt.getRows()) {
			DataTable cols = new DataTable(dmd.getColumns(null, null, row.getString("TABLE_NAME"), null));
			String[][] types = new String[cols.getRowCount()][2];
			int i = 0;
			for (MapJ col : cols.getRows()) {
				types[i][0] = col.getString("COLUMN_NAME");
				types[i][1] = DataSourceManager.getJavaTypeName(col.getString("TYPE_NAME").toLowerCase());
				i++;
			}
			Model.define(base, template, pkg + "." + WordUtils.capitalize(row.getString("TABLE_NAME")), types, funs);
		}
		conn.close();
	}

}
